package com.wngbms.netty.seatdemo.client;

import com.wngbms.netty.seatdemo.comm.CmdType;
import com.wngbms.netty.seatdemo.message.BaseHeader;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.util.UUID;

@Slf4j
public class ClientSeatInMessage {

    // 消息头
    private BaseHeader baseHeader;
    // 消息体字节数
    private int bodyLength;
    // 包括消息头在内的总字节数
    private int totalLength;
    // 已接收字节数
    private int receivedLength;
    // 可写入的消息体数组索引下标
    private int writableIndex;
    // 消息体
    private byte[] body;
    File file;
    FileOutputStream fileOutputStream;
    FileChannel fileOutChannel;

    boolean parsed;

    public BaseHeader getBaseHeader() {
        return baseHeader;
    }

    public byte[] getBody() {
        return body;
    }

    public File getFile() {
        return file;
    }

    public boolean parsed() throws IOException {
        if (!parsed) {
            if (baseHeader.isFinish()) {
                setBaseHeader(baseHeader, true);
                parsed = true;
            }
        }
        return parsed;
    }

    public void setBaseHeader(BaseHeader baseHeader, boolean parse) throws IOException {
        this.baseHeader = baseHeader;

        if (parse) {
            this.bodyLength = baseHeader.getBodyLength();
            final int headerLength = BaseHeader.HEADER_LENGTH;
            this.totalLength = headerLength + this.bodyLength;
            this.receivedLength = headerLength;

            if (baseHeader.getCmdType() != CmdType.BINARY_TEST_DOWNLOAD) {
                this.body = new byte[bodyLength];
            } else {
                String userDir = System.getProperty("user.dir");
                String fileName = UUID.randomUUID().toString();
                String fileFullPathName = userDir + File.separator + fileName + "-client";

                file = new File(fileFullPathName);
                if (!file.exists()) {
                    file.createNewFile();
                    log.info("创建文件:{}", fileFullPathName);
                }
                fileOutputStream = new FileOutputStream(file);
                this.fileOutChannel = fileOutputStream.getChannel();
            }
        }
    }

    public void setBaseHeader(BaseHeader baseHeader) throws IOException {
        setBaseHeader(baseHeader, true);
    }

    public boolean finished() throws IOException {
        boolean b = receivedLength == totalLength;
        if ((baseHeader.getCmdType() == CmdType.BINARY_TEST_DOWNLOAD) && b) {
            fileOutChannel.close();
            fileOutputStream.close();
            log.info("文件下载完毕");
        }
        return b;
    }

    public int writeBody(byte[] buf, int readableIndex, int readableLength) throws IOException {
        if (baseHeader.getCmdType() != CmdType.BINARY_TEST_DOWNLOAD) {
            int min = Math.min(readableLength, this.bodyLength - writableIndex);

            System.arraycopy(buf, readableIndex, this.body, writableIndex, min);
            writableIndex += min;
            receivedLength += min;

            return min;
        } else {
            int min = Math.min(readableLength, this.totalLength - receivedLength);
            receivedLength += min;

            fileOutputStream.write(buf, readableIndex, min);
            return min;
        }
    }

    public void writeBody(ByteBuffer buffer, int readableBytes, SocketChannel socketChannel) throws IOException {
        if (baseHeader.getCmdType() != CmdType.BINARY_TEST_DOWNLOAD) {
            int min = Math.min(readableBytes, this.bodyLength - writableIndex);
            buffer.get(this.body, writableIndex, min);
            writableIndex += min;
            receivedLength += min;
        } else {

            if (readableBytes > totalLength - receivedLength) {
                int limit = buffer.limit();

                buffer.limit(totalLength - receivedLength);
                fileOutChannel.write(buffer);
                receivedLength += (totalLength - receivedLength);
                log.info("已接收文件大小:{}, 文件总大小:{}", receivedLength - BaseHeader.HEADER_LENGTH, bodyLength);

                buffer.limit(limit);
            } else {
                fileOutChannel.write(buffer);
                receivedLength += readableBytes;
                log.info("已接收文件大小:{}, 文件总大小:{}", receivedLength - BaseHeader.HEADER_LENGTH, bodyLength);
            }

/*            int min = Math.min(readableBytes, totalLength - receivedLength);
            long transfer = fileOutChannel.transferFrom(socketChannel, receivedLength - BaseHeader.HEADER_LENGTH, min);
            log.info("本次传输{},已接收文件大小:{}, 文件总大小:{}", transfer, receivedLength - BaseHeader.HEADER_LENGTH, bodyLength);
            receivedLength += min;
            buffer.position(buffer.position() + min);*/
        }
    }

}
